<?php
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Mapping\ClassMetadataInfo;

class ZendX_Extjs_View_Helper_DoctrineForm extends ZendX_Extjs_View_Helper_Base
{
	public function doctrineForm($model, $identifier=null, array $fixedmanytoone = array())
	{
		if (is_null($identifier)) {
			$this->extjs->addOnLoad("var identifier = '';");
		}
		else {
			$this->extjs->addOnLoad("var identifier = {$identifier};");
		}
		//many-to-one
		$listeners = $this->many_to_one($model, $fixedmanytoone);
		
		//one-to-many
		$o2m = $this->one_to_many($model, $identifier);
		
		//many-to-many
		$m2m = $this->many_to_many($model, $identifier);
		
		$controllername = Zend_Controller_Front::getInstance()->getRequest()->getControllerName();	

		$formCallbacks = "";
		if (is_null($identifier)) {
			foreach ($o2m as $k=>$v){
				$formCallbacks .= "Ext.getCmp('tab_{$k}').enable();";
			}
			foreach ($m2m as $k=>$v){
				$formCallbacks .= "Ext.getCmp('tab_{$k}').enable();";
				$formCallbacks .= "notowned_{$k}_grid.store.proxy.url += action.result.id;";
				$formCallbacks .= "owned_{$k}_grid.store.proxy.url += action.result.id;";
				$formCallbacks .= "notowned_{$k}_grid.store.load();";
				$formCallbacks .= "owned_{$k}_grid.store.load();";
			}
			$formCallbacks .= "form.url='/{$controllername}/edit/model/{$model}/id/' + action.result.id;";
			$formCallbacks .= "identifier = action.result.id;";
		}
		
		$basicForm = ZendX_Extjs_View_Helper_ExtComponent::js('Ext.form.Panel', array(			
			'url'=> is_null($identifier)? "/{$controllername}/add/model/{$model}" : "/{$controllername}/edit/model/{$model}/id/{$identifier}",
//			'title'=>"add {$model}",
			'items'=>$this->_buildForm($model, $identifier, $fixedmanytoone),
			'buttons'=>array(
				array(
					'text'=>'submit',
					'handler'=>new Zend_Json_Expr("function(){var form=this.up('form').getForm();if(form.isValid()){form.submit({success:function(form,action){ {$formCallbacks} Extux.msg('success','');},failure:function(form,action){Extux.msg('failed','');}});}}")
				),array(
					'text'=>'return',
					'handler'=>new Zend_Json_Expr("function(){history.back();}")
				)
			),			
		), "{$model}_form");
		$this->extjs->addOnLoad(Zend_Json::prettyPrint($basicForm, array("indent" => " ")));
		
		$tabsConf = array(
			'renderTo'=>'form',
			'items'=> array(
				array(
					'id'=>'basic',
					'title'=>'basic',
					'items'=>array(new Zend_Json_Expr("{$model}_form")),
					'closable'=>false
				),				
			)
		);
		
		foreach ($o2m as $k=>$v){
			$tabsConf['items'][] = array(
				'id'=>"tab_{$k}",
				'title'=>"{$k}",
				'items'=>array(new Zend_Json_Expr("{$v}")),
				'closable'=>false,
				'disabled' => is_null($identifier)
			);
		}
		
		foreach ($m2m as $k=>$v){
			$tabsConf['items'][] = array(
				'id'=>"tab_{$k}",
				'title'=>"{$k}",
				'items'=>array(new Zend_Json_Expr("{$v}")),
				'closable'=>false,
				'disabled' => is_null($identifier)
			);
		}
		
		$tabs = ZendX_Extjs_View_Helper_ExtComponent::js('Ext.tab.Panel', $tabsConf);
		$this->extjs->addOnLoad(Zend_Json::prettyPrint($tabs, array("indent" => " ")));
		
		foreach ($listeners as $callback){
			$this->extjs->addOnLoad($callback);
		}
	}
	
	private function many_to_one($model, array $fixedmanytoone = array())
	{
		$registry = Zend_Registry::getInstance();	
    	//$translator = $registry->Zend_Translate;		
		$entityManager = $registry->entityManager;
		$metadata = $entityManager->getClassMetadata($model);
		
		$listeners = array();
		foreach ($metadata->associationMappings as $column => $detail)
		{
			if ($detail['type'] == ClassMetadata::MANY_TO_ONE)				
			{
				if (array_key_exists($column, $fixedmanytoone)) {
					continue;
				}
				
				$targetEntity = $detail['targetEntity'];
				
				$qb = $entityManager->createQueryBuilder();
				$qb->select("g")->from("{$targetEntity}", 'g');	
				$this->view->doctrineGrid("{$targetEntity}_grid", $qb, false, array(
						'url'=>"/Doctrinext/gridjson/model/{$targetEntity}"
					), array(
					'listeners'=>array('itemdblclick' => new Zend_Json_Expr("function(){
		var record={$targetEntity}_grid.getSelectionModel().getSelection()[0];
    	var id = record.get('id');  
    	{$model}_form.getForm().findField('{$column}').setValue(id);  	
        var name = record.get('name');
        {$model}_form.getForm().findField('{$column}_display').setValue(name);select_{$column}_win.hide();}"))
				));	

				$window = ZendX_Extjs_View_Helper_ExtComponent::js('Ext.window.Window', array(
					'title'=>"select{$column}",
					'closeAction'=>'hide',
					'height'=>400,
					'width'=>480,
					'closable'=>true,
					'maximizable'=>false,
					'items'=>array(new Zend_Json_Expr("{$targetEntity}_grid"))
				), "select_{$column}_win");
				$this->extjs->addOnLoad(Zend_Json::prettyPrint($window, array("indent" => " ")));
				
				$listeners[] = "var select_{$column}_label = Ext.get('select_{$column}');";
				$listeners[] = "select_{$column}_label.addListener('click', function(){select_{$column}_win.show();});";
			}
		}	
		
		return $listeners;
	}
	
	private function one_to_many($model, $identifier)
	{
		$o2m = array();
		
		$registry = Zend_Registry::getInstance();	
    	//$translator = $registry->Zend_Translate;		
		$entityManager = $registry->entityManager;
		$metadata = $entityManager->getClassMetadata($model);
		foreach ($metadata->associationMappings as $column => $detail)
		{
			if ($detail['type'] == ClassMetadata::ONE_TO_MANY)				
			{				
				$targetEntity = $detail['targetEntity'];
				$mapping = $detail['mappedBy'];
				if (!$mapping) {
					$mapping = $detail['inversedBy'];
				}
				
				$qb = $entityManager->createQueryBuilder();
				$qb->select("g")->from("{$targetEntity}", 'g');	
				
				$o2m[$column] = "{$column}_grid";
				
				$this->view->doctrineGrid("{$column}_grid", $qb, true, array(
					'url'=>"/Doctrinext/gridjson/get/{$targetEntity}/of/{$mapping}/withkey/{$identifier}",	
				), array(
					'addurl'=>"/Doctrinext/add/model/{$targetEntity}/owner/{$mapping}/ownerkey/{$identifier}",
					'editurl'=>"/Doctrinext/edit/model/{$targetEntity}/owner/{$mapping}/ownerkey/{$identifier}/id/",
					'deleteurl'=>"/Doctrinext/delete/model/{$targetEntity}/id/"
				));
			}
		}
		
		return $o2m;
	}
	
	private function many_to_many($model, $identifier)
	{		
		$m2m = array();
		$registry = Zend_Registry::getInstance();	
    	//$translator = $registry->Zend_Translate;		
		$entityManager = $registry->entityManager;
		$metadata = $entityManager->getClassMetadata($model);
		foreach ($metadata->associationMappings as $column => $detail)
		{
			if ($detail['type'] == ClassMetadata::MANY_TO_MANY)				
			{
				$targetEntity = $detail['targetEntity'];	
				
				//not linked
				$qb = $entityManager->createQueryBuilder();
				$qb->select("d")->from("{$targetEntity}", 'd');	
				$this->view->doctrineGrid("notowned_{$column}_grid", $qb, false, array(
					'url'=>"/Doctrinext/gridjson/get/{$targetEntity}/notlinkedto/{$metadata->name}/withkey/{$identifier}",
				), array(
					'title'=>'not linked',
					'margins'=>'0 2 0 0',
					'multiSelect'=>true,
					'viewConfig'=>array(
						'plugins'=>array(
							'ptype'=>'gridviewdragdrop',
							'dragGroup'=>"notowned_{$column}_gridDDGroup",
							'dropGroup'=>"owned_{$column}_gridDDGroup"),
						'listeners'=>array(						
							'drop'=>new Zend_Json_Expr("function(node,data,dropRec,dropPosition){var ids=new Array();for(var i=0;i<data.records.length;i++){var item=data.records[i];var id=item.get('id');ids.push(id);}Ext.Ajax.request({url:'/Doctrinext/moveout/remove/{$targetEntity}/from/{$column}/of/{$model}/withkey/'+identifier+'/',dataType:'json',params:{data:JSON.stringify(ids)}});}"),						
							'itemdblclick'=>new Zend_Json_Expr("function(){var record=notowned_{$column}_grid.getSelectionModel().getSelection()[0];var ids=new Array();	var id=record.get('id');	ids.push(id);Ext.Ajax.request({url:'/Doctrinext/movein/add/{$targetEntity}/to/{$column}/of/{$model}/withkey/'+identifier+'/',dataType:'json',params:{data:JSON.stringify(ids)},success:function(response){notowned_{$column}_grid.getStore().remove(record);owned_{$column}_grid.getStore().add(record);}});}")
						)
					),					
				));
				
				$this->view->doctrineGrid("owned_{$column}_grid", $qb, false, array(
					'url'=>"/Doctrinext/gridjson/get/{$targetEntity}/linkedto/{$metadata->name}/withkey/{$identifier}",
				), array(
					'title'=>'linked',
					'margins'=>'0 0 0 3',
					'multiSelect'=>true,
					'viewConfig'=>array(
						'plugins'=>array(
							'ptype'=>'gridviewdragdrop',
							'dropGroup'=>"notowned_{$column}_gridDDGroup",
							'dragGroup'=>"owned_{$column}_gridDDGroup"
							),
						'listeners'=>array(
							'drop'=>new Zend_Json_Expr("function(node,data,dropRec,dropPosition){var ids=new Array();for(var i=0;i<data.records.length;i++){var item=data.records[i];var id=item.get('id');ids.push(id);}Ext.Ajax.request({url:'/Doctrinext/movein/add/{$targetEntity}/to/{$column}/of/{$model}/withkey/'+identifier+'/',dataType:'json',params:{data:JSON.stringify(ids)}});}"),					
							'itemdblclick'=>new Zend_Json_Expr("function(){var record=owned_{$column}_grid.getSelectionModel().getSelection()[0];var ids=new Array();	var id=record.get('id');	ids.push(id);Ext.Ajax.request({url:'/Doctrinext/moveout/remove/{$targetEntity}/from/{$column}/of/{$model}/withkey/'+identifier+'/',dataType:'json',params:{data:JSON.stringify(ids)},success:function(response){notowned_{$column}_grid.getStore().add(record);owned_{$column}_grid.getStore().remove(record);}});}")						
						)
					),
					
				));
				
				$m2m[$column] = "{$column}_panel";
				$panel = ZendX_Extjs_View_Helper_ExtComponent::js('Ext.Panel', array(
					'width'=>700,
					'height'=>300,
					'defaults'=>array('flex'=>1),
					'layout'=>array(
						'type'=>'hbox',
						'align'=>'stretch'
					),
					'items'=>array(new Zend_Json_Expr("notowned_{$column}_grid"),new Zend_Json_Expr("owned_{$column}_grid"))
				), "{$column}_panel");
				$this->extjs->addOnLoad(Zend_Json::prettyPrint($panel, array("indent" => " ")));
			}
		}
		
		return $m2m;
	}
	private function _buildForm($model, $identifier=null, array $fixedmanytoone = array())
	{
		$registry = Zend_Registry::getInstance();	
    	//$translator = $registry->Zend_Translate;
    	$entityManager = $registry->entityManager;
    	
    	$entity = is_null($identifier) ? new $model : $entityManager->find($model, $identifier);
    	
		$items = array();
		
		$metadata = $entityManager->getClassMetadata($model);
		foreach ($metadata->fieldMappings as $field => $def)
		{
			$item = array();
			
			if (isset($def['options']) && isset($def['options']['render']) 
				&& !$def['options']['render']) 
			{
				continue;;
			}
			
			//xtype
			if (in_array($field, $metadata->identifier)
					&& ! $metadata->isIdentifierNatural())
			{
				$item['xtype'] = "hidden";
			}
			else if (isset($def['options']) && isset($def['options']['rendertype']))
			{
				$item['xtype'] = $def['options']['rendertype'];
			}
			else if (in_array($def['type'], array('integer','smallint','bigint','decimal','float'))) {				
				$item['xtype'] = "numberfield";
				$item['decimalPrecision'] = 4;
			}
			else if ($def['type'] == "date") {
				$item['xtype'] = "datefield";
			}
			else if ($def['type'] == "time") {
				$item['xtype'] = "timefield";
			}
			else if ($def['type'] == "datetime") {
				$item['xtype'] = "datefield";
			}
			else if (isset($def['columnDefinition'])
				&& substr($def['columnDefinition'], 0, 4) == 'ENUM') {
				$item['xtype'] = "combo";
				$item['displayField'] = "name";
				$item['valueField'] = "value";
				
				$enums = substr($def['columnDefinition'], 5, strlen($def['columnDefinition'])-6);
				$enumarray = explode(',', $enums);
				$tmp = array();
				foreach ($enumarray as $e)
				{		
					$tmp[] = $e . " => " . $e;																				
				}
				$str = implode(',', $tmp);
				$default = eval("return array($str);");	
				$data = array();
				foreach ($default as $e)
				{
					$data[] = array('value'=>$e, 'name'=>$e);
				}				
				$item['store'] = array(
					'fields' => array('value', 'name'),
					'data' => $data,
				);
			}
			else 
			{
				$item['xtype'] = "textfield";
				if ($field == "email")						
					$item['vtype'] = "email";
						
			}
			$item['columnWidth'] = ".5";
			$item['name'] = $field;

			$item['fieldLabel'] = $field;	
			
			//nullable
			if (array_key_exists('nullable', $def) && (! $def['nullable']))
			{
				$item['allowBlank'] = false;
			}
			
			//value		
			$item['value'] = $entity->$field;
			
			$items[] = $item;
		}
		
		//many-to-one
		foreach ($metadata->associationMappings as $column => $detail)
		{
			if ($detail['type'] == ClassMetadata::MANY_TO_ONE)				
			{
				$item = array(
					'xtype' => 'hidden',
					'name'=>$column,
					'value'=> is_null($identifier)? "" : $entity->$column->id			
				);
				if (isset($fixedmanytoone[$column])) {
					$item['value'] = $fixedmanytoone[$column];	
				}
				$items[] = $item;
				
				if (! isset($fixedmanytoone[$column])) {
					$items[] = array(
						'xtype'=>'textfield',
						'name'=>"{$column}_display",
						'readOnly'=>true,
						'fieldLabel'=>"<a id='select_{$column}' href=# style='text-decoration:underline'>{$column}</a>",
						'value'=>is_null($identifier)? "" :$entity->$column->name				
					);
				}
			}
		}
					
		return $items;
	}	
}